<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" session="false" %>
<%
	String path = request.getContextPath();
	pageContext.setAttribute("path", path);
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>oo</title>
<script type="text/javascript">
	// 类和函数一样
	// new的时候是构造函数，非new的时候是普通函数
	// 是Function类的一个实例
	function Animal(name){
		var dd=1; // 私有变量，没有闭包使用的话就会实例化后就会被垃圾回收
		// 私有方法
		function priMethod(){

		}
		this.name = name;
		this.age = 0;
		// 每次初始化都要初始化这个函数对象
		// 特权方法，可以访问私有、共有所有成员
		this.sayHello = function(){
			dd++;
			alert(this.name + ":" + this.age);
		};
	}
	// 方法定义在外面
	// 只能访问类的成员（公开属性）
	Animal.prototype.test = function(){
		alert(this.name + ":" + this.age);
		alert(this.dd); // dd变量不能访问（私有属性）
	};

	// 类的定义
	function testClass(){
		var a1 = Animal; // 类
		var a2 = Animal();
		var a3 = new Animal(); // 当作类来用
		var a4 = new Animal; // 同new Animal()
		alert(a1); // 函数定义
		alert(a2); // undifined 没有返回值
		alert(a3); // object
		alert(a4); // object
		//console.dir(a1);
		//console.dir(a2);
		//console.dir(a3);
		//console.dir(a4);
		// 是不是Animal的实例
		alert(a3.constructor == Animal);
	}

	function sum(a, b, c, d){
		return a + b + c + d;
	}

	// 不能重载，利用可变参数进行类型和个数的判断实现重载
	// 函数可变参数
	function sum1(){
		// 取到参数数组
		var sum = 0;
		for(var i=0, len=arguments.length; i<len; i++){
			sum += arguments[i];
		}
		return sum;
	}

	function testSum(){
		alert(sum(1, 3)); // NaN 参数没传值加上去报错
		// js不允许重载方法，只有最后一个起作用
		alert(sum(1, 2, 3, 4));
	}

	// 对象类型和构造函数判断
	// js中所有的都是对象，函数是特殊的对象
	function testTC(){
		var s1 = function(){
			return 1;
		};
		alert(typeof s1); // 类型是function
		alert(s1.constructor); // 构造函数是function Function(){}
		var a1 = [1, 2];
		alert(typeof a1); // 是对象不是数组
		alert(a1.constructor); // function Array(){}
		var d1 = 12;
		alert(typeof d1); // number对象
		// 判断是不是数组
		if(typeof a1 == "object" && a1.constructor == Array){
			alert(true);
		}
	}

	// 动态函数
	function testFunction(){
		// 每个函数都是Function的一个实例
		var s2 = new Function("alert(1)");
		s2();
	}

	// 函数嵌套函数
	function f1(){
		var d=0;
		var f2 = function(){
			// 不被垃圾回收
			d++;
			alert(d);
		};
		return f2;
	}

	// 函数闭包，可以访问函数内部的变量
	// 用于封装，类似java的get/set方法
	function testClosure(){
		var f3 = f1(); // f1没被回收
		f3();
		f3();
		// f3被清理，f1被清理，d也被清理收回
		f3 = null;
	}

	// 替代简单对象 {v: "this is b1"}
	// var obj = new Object();
	// obj.v = "this is b1";
	var b1 = {v: "this is b1"};
	var b2 = {v: "this is b2"};
	function b(d, r){
		alert(this.v + d + r);
	}
	var b3 = {v: "this is b3", sayHello: function(){
		alert(this.v);
	}};

	// 函数作用域和this
	// this谁引用（"."和new操作符，没有操作符是window.）就指向谁
	// 执行函数的三个方法
	function testScope(){
		b("111", "222"); // this是window，实际上就是window.b()
		window.b("111", "222"); // this是window
		// call 第一个参数是函数的上下文，后面是原参数
		b.call(b1, "111", "222"); // b.call()等于b() this指向b1
		// apply 第一个参数是函数的上下文，后面必须是个数组
		b.apply(b2, ["111", "222"]); // b.apply()等于b() this指向b2
		b3.sayHello.call(b1); // 借用别人的方法
	}

	// 数组方式访问对象成员
	function testPropertyByArray(){
		// 特殊
		var b = {11: 55};
		// alert(b.11); // 不能访问不是一个正确的标识符
		alert(b["11"]); // 这样可以
	}

	// 列举对象成员
	function testListObject(){
		var b = {v: "this is b3", sayHello: function(){
			alert(this.v);
		}};
		// for ... in 循环对象属性
		// IE调试的时候可以在一个DIV输出这些对象属性
		for(var key in b){
			alert(key + ":" + b[key]);
		}
	}

	// 动态删除成员
	// 释放内存
	function testDelelte(){
		var b = {v: "this is b3", sayHello: function(){
			alert(this.v);
		}};
		delete b.v;
		alert(b.v);
	}

	// 类的修改
	function testModify(){
		// var d = 5; // 不行动态添加？
		var d = new Number(5);
		// 给一个实例添加
		// 先找实例本身的函数，然后再去类的prototype里面找同名函数
		d.add = function(b){
			return this + b;
		};
		alert(d.add);
		alert(d.add(4));
		// prototype属性，给所有的实例添加
		alert(d.remove);
		Number.prototype.remove = function(b){
			return this - b;
		};
		var c = 111;
		alert(c.remove(11).remove(11));
		// 延迟绑定，添加了才使用
		alert(d.remove(4));
	}

	function classA(name){
		this.name = name;
		this.showName = function(){
			alert(this.name);
		};
	}

	function classB(name){
		this.newMethod = classA;
		// 此时classA中的this指向classB
		// 执行classA这个函数，并把它的上下文指向this（b的实例）
		this.newMethod(name);
		// classA.call(this, name);
		// classA.apply(this, [name]);
		delete this.newMethod; // 使用完删除动态的
		// 如果是
		// classA(name); // 相当于window.classA(name); classA中的this指向window
	}

	// 类的继承，函数执行方式
	function testExtend1(){
		var objA = new classA("objA");
		var objB = new classB("objB");
		objA.showName(); // hero
		objB.showName(); // dby
		var o = classA("window"); // 相当于执行函数，this指向window
		window.showName();
	}

	function classC(){

	}

	// 类的继承，原型链方式
	function testExtend2(){
		// 这样加是怎么加的？
		classC.prototype = new classB("objB");
		var objc = new classC();
		objc.name = "objc"; // 变为常量
		objc.showName();
	}

	// 多态

	// testClass();
	// testSum();
	// testTC();
	// testFunction();
	// testClosure();
	// testScope();
	// testPropertyByArray();
	// testListObject();
	// testDelelte();
	// testModify();
	// testExtend1();
	// testExtend2();
</script>
</head>
<body>
</body>
</html>
